home *** CD-ROM | disk | FTP | other *** search
-
-
-
- CONCURRENT PROGRAMMING IN TURBO C
- ======================================
-
-
- Documentation with "CONCUR.C" Richard Dickerson
- Version 1.00 4129 Friendly Way
- Date : Oct 15th, 1988 Memphis, TN 38115
- CIS ID: 73346,1217
-
-
- Introduction
- ------------
-
- A couple of years ago, I came across a concurrent programming
- module called CONCUR.PAS written by Hans Passant. At the time, a
- similar set of routines didn't exist for the C programming
- language, so I set out to use Mr. Passant's inspiration to
- develop CONCUR.C. About the time I was finishing CONCUR.C,
- Thomas Wagner developed CTASK.C - a routine that enables true
- multi-tasking. Although this program module is less ambitious
- than CTASK.C, it is smaller and easier to use, and has built-in
- window management routines that CTASK.C lacks. I have used Mr.
- Passant's ideas, but the mechanism for saving and restoring task
- stacks and windows is slightly different owing to the differences
- between Pascal and C.
-
- Multi-tasking is a process where several independent pieces of
- code (tasks) compete for execution. Obviously, the CPU can
- execute only one task at a time. The trick is to allow each task
- to execute for a small amount of time, after which the next task
- is executed. If this happens often enough, the computer appears
- to run all of the tasks at the same time : true multi-tasking
- behavior.
-
- The process of suspending the currently active task and
- activating the next is called a "context-switch". All variables
- that are used by the task to be suspended (the task-context) must
- be saved so the task can be reactivated and continue where it
- left off when the task is again eligible for execution. Generally
- the task-context is made up of the current processor registers
- and the stack. Saving all the registers and preserving the task
- stack is therefore enough.
-
- Turbo C is perfectly suited for this type of context-switch. It
- saves all of its function parameters and local variables on the
- stack. The context of each task can therefor be preserved by
- allocating a stack for each individual task. The task-context
- switch function then only has to save the processor registers on
- the task-stack, set the stackpointer to the task stack for the
- next task to execute and restore the registers for that task.
- There is however a catch, some variables used in the Turbo C
- library belong to the task-context (Example : the _video
- variable). Also, the programmer may introduce some global
- variables that are used by more than one task. The kernel takes
- care for the shared library variables. It saves them in global
- structures stack upon a context-switch. The programmer is
- responsible for protecting the shared use of any global
- variables. An example is given in the kernel-code.
-
- Left to discuss is the mechanism that forces a context switch.
- True multi-tasking operating systems always use a hardware
- interrupt, triggered by a timer. The mechanism used in CONCUR.C
- is a simple coded call to the context-switch function. This
- method is known as "concurrent programming" and is popularized by
- MODULA-2 . The disadvantage of the latter mechanism is that
- a context switch does not occur until explicitly called
- for. A badly coded task may contain a long or infinite loop
- without a call to the context switch function. The task
- continues to execute without any concurrent tasks being
- executed.
-
- The big advantage of concurrent programming however is the
- simplification of the kernel. A hardware triggered context
- switch may suspend a task that is executing a library routine.
- The Turbo C library is non-reentrant (for the same reasons DOS is
- non-reentrant). The kernel would therefor have to save all
- library data structures on a context switch, a very time-
- consuming operation.
-
-
-
- Tasks
- -----
-
- Tasks in CONCUR are simple, parameterless Turbo functions. Each
- task has a tasknumber and a private area in the Turbo
- stack segment for its stack : the task stack. A program always
- contains one task : the main program. By convention it has task
- number 0. Other tasks are eligible for execution by installing
- them. The install function claims an area of memory for the task
- stack and creates a stack frame for the task. Once a task is
- installed it can never end execution and must never call another
- one directly.
-
- The task install function needs the start address for the task ,
- the stack size needed, and the task number. The amount of stack
- needed for a task depends on the size of its local variables and
- the recursion depth (if any). Failing to assign enough stack
- to a task may cause erratic program behavior at worst or a
- "stack overflow" or "heap/stack" collision run time error at
- best.
-
- The task stacks
- ---------------
-
- Each task participating in the concurrent programming scheme is
- assigned a reserved area in the Turbo stack segment for its own
- stack. This area should be reserved at start-up of the program.
- A call to the function <installtask> takes a chunk from the
- stack and assigns it to the task being installed. A stack
- pointer is created, pointing into the stack, and is saved into
- the global structure jpr[taskind], where taskind is the current
- task index. The task stack is initialized with the register
- contents for the task. The task is now ready to run, activated
- by a call to <switchta>.
-
-
-
- Task switching
- --------------
-
- The concurrent programming method hinges around the function
- <switchta>. This function is responsible for the context
- switch needed to deactivate the current task and activate the
- next. <switchta> takes the following steps :
-
- 1. Saves all data registers on the stack.
- 2. Checks the stack pointer for any stack overflow.
- 3. Saves the stack pointer (SS:SP) in the global
- structure jpr[<taskind>].
- 4. Scans <maxtasks> for the next installed task.
- 5. Retrieves the stack pointer for that task.
- 6. Assigns <taskind> the task number of the new task.
- 7. Restores all data registers from the new task's stack.
- 8. Continues execution in the new task.
-
- Task switching does not occur until <switchta> is called. This
- restriction makes the distinction between concurrent programming
- and multi-tasking. A multi-tasking system initiates task
- switching independent from whatever task is running, usually
- triggered by a clock interrupt. This means that when your
- program should behave like a true multi-tasking program, the
- tasks should call <switchta> frequently and should avoid lengthy
- execution.
-
-
- Sharing input
- -------------
-
- The above mentioned restrictions imposed by the concurrent
- programming model are most severe when reading from the keyboard.
- Whenever a keyboard function <cgets, getch, getche ...) is coded,
- Turbo C transfers control to a library function that accepts
- keyboard input and only returns when "Enter" is pressed. While
- this is happening, no calls to <switchta> are made : the entire
- program "hangs" until input is ready.
-
- CONCUR.C contains a replacement <getche> function that avoids
- the input problems. It is left to the programmer to provide
- similar string input functions.
-
- The keyboard must be shared when two or more tasks need input.
- The functions <claiminput> and <releaseinput> take care of
- that. A task needing input calls <claiminput>. The flag
- <inputbusy> is set. The task now gets control over <input>. As
- soon as input is completed, <releaseinput> is called, releasing
- the keyboard for other tasks.
-
- Another task needing input should call <claiminput> too. If it
- finds <inputbusy> set, <switchta> is called until the first
- task claiming <input> releases the keyboard, allowing the second
- task to take control over the keyboard.
-
-
- Sharing output
- --------------
-
- The above mentioned sharing problems also exist for output to the
- screen. Switchta.obj therefore automatically manages the screen
- output for all tasks that use functions outputting directly to
- the console(cprintf, cputs, ...). Each concurrent task has its
- own window on the screen. Initially, each task gets a window of
- full screen size. Upon activation, the task should call the
- function <taskwindow> to shrink its window to a part of the
- screen reserved for that task. The function <border>
- optionally draws a border around that window.
-
-
-
- Function entries
- ----------------
-
- The following functions in CONCUR.C may be called :
-
-
- - void installtask (int Task number, paragraphs, *function). This
- function should be called to install a task. <Function> is
- the function name of the task and must be of the type
- void <task name(void)>". <Paragraphs> is the amount of
- stack needed by the task (in paragraphs).
- <Task_number> is the task number for the installed task and
- should range from 1 to 15.
-
- - void switchta(void). This function does the context switch
- from the currently active task to the next installed task.
- Switchta() also preserves and restores the task windows and
- text attributes.
-
- - void taskwindow (int x1,y1,x2,y2,attribute). This function
- should be called by each task (including task 0, the main
- program !!) to reserve a portion of the screen for its
- output. <x1, y1> are the screen coordinates for the upper
- left corner, <x2, y2> is the lower right corner, and
- <attribute> is the attribute for window text. Each call to
- <switchta> will preserve and restore these values for
- the task window. In this manner, one window may have
- blinking text while the others may have normal,
- inverse, high, or low video attributes.
-
- - void border (char *name). Draws a border around the window of
- the current task. <name> is shown centered on top of the
- window.
-
-
-
- Program design
- --------------
-
- The following basic steps should be made when designing a program
- using the concurrent programming method :
-
- 1. Make a logical division in your program into actions that
- should occur concurrently. This will produce the tasks.
- Remember that the main program always acts as one of the
- tasks, you may want to use it to monitor the execution of the
- entire program. Avoid having too many tasks, the more tasks
- are present, the slower each of them will run.
-
-
- 2. Choose a screen layout for the windows of each task producing
- screen output. If you have a color monitor, be liberal with the
- use of TextColor and TextBackground. Have the tasks call
- <taskwindow>/<border> as soon as they start execution.
-
- 3. Write the code for each concurrent task. Decide where calls to
- <switchta> should be made. Each concurrent task should at least
- contain an infinite loop, so a call should be made inside that
- loop. Inspect other loops and place calls at the deepest nesting
- levels.
-
- 4. Include the header-files :
- 1. #include <concur.h>
- 2. #include <stdio.h>
- 3 #include <conio.h>
-
-
- 5. Inspect your code for tasks that need input from the keyboard.
- If at least two tasks need input, surround the input code with
- calls to <claiminput> and <releaseinput>.
-
- 6. Inspect your code for shared access to global variables, files
- and devices. Access may need to be controlled through an
- access flag. Example :
-
- void claimvar(void) /* function */
- {
- while (var_in_use) switchta(); /*claimvar*/
- var_in_use = 1;
- } /*releasevar*/
-
- void releasevar(void); /*function task2*/
- {
- var_in_use = 0; /*claimvar*/
- }
- /*releasevar*/
-
-
- A prototype task would be coded as follows :
-
- void task1(void)
- {
- textbackground (..);/*Background color for task window*/
- taskwindow (.....); /*Create task window*/
- textcolor (..); /*Color for border*/
- border (....); /*Create border around window*/
- textcolor (..); /*Color for text in window*/
- do
- {
- ....
- switchta(); /*At least one call to switchta*/
- }
- while (1!=0); /*Task should contain infinite loop*/
- };
-
-
-
- 7.Compile using the small model libraries, and link in the file
- <SWITCHTA.OBJ>.
- Restrictions
- ------------
-
- 1. Access to global variables by more than one task is dangerous.
- A sharing protocol is needed, similar to the <inputbusy>
- method employed by the input driver.
-
- 2. A maximum of 15 tasks may be installed.
-
- 3. Screen I/O must use cprintf(),cputs(),cscanf() and the
- replacement getche() function to work within the task windows.
-
- 4. The installed tasks MUST be parameterless !!!
-
-
-
- Problems and error messages
- ---------------------------
-
- The following error messages may appear, they will abort the
- program :
-
- - "Task Error: Unexpected End of Task ...". Installed
- tasks are not allowed to abort. Revise your code
- and make sure a task contains an infinite loop.
-
- - "Install Error: Illegal task number ...". Task numbers
- should be in (1..15).
-
- Failing to request enough stack space for a task may result in
- erratic behavior of the program. The stack of another task may be
- destroyed without Turbo or CONCUR detecting the error. Make sure
- enough stack space is reserved for each task. As a rule of thumb,
- add the size of all local variables and divide by 16 to get the
- number of paragraphs. Add 20 for safety. If the task does any
- recursion, add plenty more (depending on the maximum recursion
- depth).
-
- Files in CONCUR.ARC
- -------------------
-
- 1. CONCUR.C - The prototype program.
- 2. CONCUR.H - The header file for CONCUR.C
- 3. SWITCHTA.OBJ - Task switching object file. Link this
- with your program.
- 4. SWITCHTA.ASM - The source for switchta.obj
- 5. CONCUR.DOC - This file.
-
-
-
- I am looking forward to your experience with CONCUR.C. Please
- let me now if you find any serious errors, particularly the ones
- that will hang up your computer. My user ID on the COMPUSERVE
- network is [73346,1217].
-
-
- Richard Dickerson
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ----------------end-of-author's-documentation---------------
-
- Software Library Information:
-
- This disk copy provided as a service of
-
- The Public (Software) Library
-
- We are not the authors of this program, nor are we associated
- with the author in any way other than as a distributor of the
- program in accordance with the author's terms of distribution.
-
- Please direct shareware payments and specific questions about
- this program to the author of the program, whose name appears
- elsewhere in this documentation. If you have trouble getting
- in touch with the author, we will do whatever we can to help
- you with your questions. All programs have been tested and do
- run. To report problems, please use the form that is in the
- file PROBLEM.DOC on many of our disks or in other written for-
- mat with screen printouts, if possible. The P(s)L cannot de-
- bug programs over the telephone.
-
- Disks in the P(s)L are updated monthly, so if you did not get
- this disk directly from the P(s)L, you should be aware that
- the files in this set may no longer be the current versions.
-
- For a copy of the latest monthly software library newsletter
- and a list of the 1,400+ disks in the library, call or write
-
- The Public (Software) Library
- P.O.Box 35705 - F
- Houston, TX 77235-5705
- (713) 665-7017
-